package com.quan.common.configuration;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import com.alibaba.fastjson.JSON;
import com.quan.common.bean.R;
import com.quan.common.properties.SystemValueProperties;
import com.quan.common.utils.JwtTokenUtils;
import com.quan.common.utils.RedisUtils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import lombok.extern.slf4j.Slf4j;

/**
 * Token验证拦截器
 * @author yhaoquan
 *
 */
@Slf4j
@Component
public class WebSecurityAuthTokenInterceptor implements HandlerInterceptor {

	@Autowired
	private RedisUtils redisOperator;

	@Autowired
	private SystemValueProperties properties;

	/**
	 * 这个方法是在访问接口之前执行的，我们只需要在这里写验证登陆状态的业务逻辑，就可以在用户调用指定接口之前验证登陆状态了
	 */
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		// 验证Token，判断用户是否登录
		if (!validToken(request)) {
			response.reset();
			response.setContentType("application/json; charset=utf-8");
			ServletOutputStream out = response.getOutputStream();

			R loginTimeOut = R.loginTimeOut();
			String message = JSON.toJSONString(loginTimeOut);

			out.write(new String(message).getBytes());

			log.warn("==>Token 验证失败：状态码[{}]，错误消息：{}，URL：{}", loginTimeOut.getStatus(), loginTimeOut.getMsg(), request.getRequestURL().toString());
			
			return false;
		} else {
			return true;
		}
	}

	/**
	 * 验证登录Token
	 * 
	 * @param request
	 * @return
	 */
	public boolean validToken(HttpServletRequest request) {
		String token = request.getHeader("token");

		// Token为空
		if (null == token || "".equals(token.trim())) {
			return false;
		}

		Jws<Claims> parse = JwtTokenUtils.parse(token, properties.getJwt().getSecret());
		if (null != parse) {
			Claims body = parse.getBody();
			boolean hasTokenKey = this.redisOperator.hasKey("sso:token:" + body.get("userId"));
			if (hasTokenKey) {
				this.redisOperator.expire("sso:token:" + body.get("userId"),
						Long.parseLong(properties.getJwt().getTimeout()));
				return true;
			} else {
				this.redisOperator.del("sso:token:" + body.get("userId"));
				return false;
			}
		} else {
			return false;
		}
	}

}
